package vip.george.security.wrapper;


import org.springframework.util.CollectionUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *  自定义RequestWrapper，实现请求体的多次读
 *  注意：本项目中任何其他的自定义RequestWrapper必须继承该类，防止过滤器链中Request类型传递错误
 *
 * @author gehaodong
 **/
public class CommonRequestWrapper extends HttpServletRequestWrapper {


    /**
     * 存储header数据,这样做的目的是不能通过HttpServletRequest直接设置请求头，这里间接的保存了请求头信息
     * 并重写了getHeader方法
     */
    private final Map<String, String> headerMap = new ConcurrentHashMap<>();

    /**
     * get请求的所有请求参数
     */
    Map<String, String[]> parameterMap;

    //    //请求数据
//    private String body;
    //请求二进制数据
    private byte[] bytes;

    public CommonRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);

        try (ServletInputStream inputStream = request.getInputStream()) {
            int contentLength = getContentLength();
            if (contentLength > 0) {
                bytes = new byte[contentLength];
                int bytesRead = inputStream.read(bytes);
                if (bytesRead != contentLength) {
//                    log.warn("不完整的body字节数组长度. Expected {}, but only read {}", contentLength, bytesRead);
                }
            } else {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                int nRead;
                byte[] data = new byte[16384]; // 16KB buffer size
                while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                bytes = buffer.toByteArray();
            }
            String s = new String(bytes, StandardCharsets.UTF_8);
//            log.info("CommonRequestWrapper的byte长度：{}", bytes.length);
        }
        //获取请求参数
        parameterMap = new HashMap<>(super.getParameterMap());
    }

    @Override
    public int getContentLength() {
        if (Objects.isNull(bytes) || bytes.length == 0) {
            return super.getContentLength();
        } else {
            return bytes.length;
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        //这一步最关键
        //这一步使得后续获取InputStream都是这个对象
        //而在此时我们也把我们自定义的数据塞进去了
        //也就是说后续处理中获取到的参数就是我们此时塞进去的数据
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ServletInputStream inputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            //这里流的读取，就是从我们自定义流中读取数据
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return inputStream;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }




    public void setParameterMap(Map<String, String[]> parameterMap) {
        this.parameterMap = parameterMap;
    }


    @Override
    public String getParameter(String name) {
        if (CollectionUtils.isEmpty(this.parameterMap)) {
            this.parameterMap = new HashMap<>(super.getParameterMap());
        }

        String[] parameterValues = getParameterValues(name);
        if (Objects.nonNull(parameterValues) && parameterValues.length > 0) {
            return parameterValues[0];
        }
        return null;
    }

    @Override
    public String[] getParameterValues(String name) {
        if (CollectionUtils.isEmpty(this.parameterMap)) {
            this.parameterMap = new HashMap<>(super.getParameterMap());
        }
        return parameterMap.get(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        if (CollectionUtils.isEmpty(this.parameterMap)) {
            this.parameterMap = new HashMap<>(super.getParameterMap());
        }
        return this.parameterMap;
    }




    /**
     * add a header with given name and value
     *
     * @param name
     * @param value
     */
    public void addHeader(String name, String value) {
        headerMap.put(name, value);
    }

    @Override
    public String getHeader(String name) {
        String headerValue = super.getHeader(name);
        if (headerMap.containsKey(name)) {
            headerValue = headerMap.get(name);
        }
        return headerValue;
    }
}